const { app, ipcMain, Tray, Menu, BrowserWindow, dialog } = require("electron");
const path = require("path");
const { fileObj } = require('./tools/file')
const { TaskRunner } = require("concurrent-tasks");
let directory = path.resolve(__dirname, "../../") + "\\hiprintStorage";

// 新建并发任务，并发数1
const runner = new TaskRunner({
    concurrency: 1,
});
// task map
const taskMap = {};
let printerMap = {};
let defaultPrinter = null;
// 托盘
function appQuit() {
    sio.close()
    MAIN_WINDOW && MAIN_WINDOW.destroy();
    app.quit();
};
function initTray() {
    let trayPath = path.join(app.getAppPath(), "/src/assets/icon.ico");
    APP_TRAY = new Tray(trayPath);
    APP_TRAY.setToolTip("CUSIN Print"); // 托盘标题
    // 托盘菜单
    let trayMenuTemplate = [
        {
            label: "退出",
            click: () => {
                MAIN_WINDOW.destroy();
                APP_TRAY.destroy();
                appQuit();
            },
        },
    ];
    const contextMenu = Menu.buildFromTemplate(trayMenuTemplate);
    // 设置右键菜单
    APP_TRAY.setContextMenu(contextMenu);
    // 监听点击事件
    APP_TRAY.on("click", function () {
        if (MAIN_WINDOW.isMinimized()) {
            MAIN_WINDOW.restore();
        }
        if (!MAIN_WINDOW.isVisible()) {
            MAIN_WINDOW.show();
            MAIN_WINDOW.setSkipTaskbar(true);
        }
    });
    return APP_TRAY;
}
async function wait(ms) {
    return new Promise((resolve) => setTimeout(() => resolve(), ms));
}
function noRepeat(arr) {
    let hash = {};
    let newArr = arr.reduce((item, next) => {
        // hash[next.code] ? "" : (hash[next.code] = true && item.push(next));

        if (hash[next.code]) {
            item.forEach((it) => {
                if (it.code == next.code) {
                    it.enable = next.enable;
                }
            });
        } else {
            hash[next.code] = true;
            item.push(next);
        }

        return item;
    }, []);

    return newArr;
}

async function syncPrinter(timeout = 10000) {
    let printerTxt = await fileObj.readFileFn(directory + "\\printer.txt");
    let data = {
        clientId: machineId,
        clientMac: addressArg.mac,
        list: [],
    };
    let printerList = await MAIN_WINDOW.webContents.getPrintersAsync().then(res => res);
    let list = [];
    if (printerTxt == "") {
        for (const printer of printerList) {
            if (printer.status == 0) {
                list.push({
                    code: printer.name + "_" + crypto.randomInt(9999),
                    name: printer.name,
                    alias: printer.alias || printer.name,
                    //打印机类型（0USB，1网络，2蓝牙）
                    type: 0,
                    status: printer.status,
                    options: printer.options,
                    isDefault: printer.isDefault,
                });
            }
        }
        data.list = list;
    } else {
        printerList.forEach((item) => {
            printerTxt.forEach((it) => {
                if (item.name == it.name) {
                    item.code = it.code;
                    item.alias = it.alias || it.name;
                    item.enable = it.enable || false;
                }
            });

            item.code == null &&
                (item.code = item.name + "_" + crypto.randomInt(9999));
        });
        data.list = printerList;
    }

    printerList.forEach((printer) => {
        if (printer.isDefault) {
            defaultPrinter = printer;
        }
        printerMap[printer.name] = printer;
    });

    // console.log("上报云端数据", data);
    //打印机上报云端
    let newPrinterList = await sio.writeSync("print.syncPrinter", data, timeout);
    // console.log("自动上报后的打印机", newPrinterList);

    if (newPrinterList) {
        //TODO 需要保存服务器下发的打印机
        let copyData = [...data.list, ...newPrinterList];

        let noRepeatData = noRepeat(copyData);
        fileObj.writeInNoAppend(directory + "\\printer.txt", noRepeatData);
        return true;
    }
    return false;
}
async function initSocketNioClient() {
    let host = await fileObj.getConfigItem("host");
    let port = await fileObj.getConfigItem("port");
    // console.log("创建SocketNio客户端", host, port);
    //创建SocketNio客户端
    sio.build({
        host,
        port,
        appKey: "TEST-PRINTER" + "[" + machineId + "]",
        secret: "zCcXJm/6zX/MsISl",
    });

    // 单个打印-printNow(数据data是从前端接口printNow参数传递过来)
    sio.addMethod("printNow", function (data) {
        let printer = printerMap[data.printerName];
        if (!printer) {
            if (defaultPrinter) {
                printer = defaultPrinter;
            } else {
                sio.writeAck("print.Error", {
                    msg: "打印机不存在，请重新选择",
                });
                return;
            }
        }
        // 向并发中添加任务
        runner.add((done) => {
            data.printer = printer;
            // 使用时间戳作为并发任务id
            let taskId = new Date().getTime();
            // 在taskMap中添加任务done事件
            taskMap[taskId] = done;
            data.taskId = taskId;

            data.html = "";
            PRINT_WINDOW.webContents.send("print-new", data);
        });
        MAIN_WINDOW.webContents.send("printTask", Object.keys(taskMap).length);
    });

    // newPrintTask  - 创建打印任务
    // printTaskList - 分段传输打印数据（多次）
    // printTaskNow  - 传输完成立即打印

    //创建打印任务
    sio.addMethod("newPrintTask", function (data) {
        newPrintTask = data.key;
    });

    // 分段传输打印数据，目前设置的最大数量为100条
    let printTaskList = {};
    //(数据data是从前端接口printNow参数传递过来)
    sio.addMethod("printTaskList", function (data) {
        printTaskList = data;
    });

    //传输完成立即打印
    sio.addMethod("printTaskNow", function (val) {
        let printer = printerMap[printTaskList.printerName];

        if (!printer) {
            if (defaultPrinter) {
                printer = defaultPrinter;
            } else {
                sio.writeAck("print.Error", {
                    msg: "打印机不存在，请重新选择",
                });
                return;
            }
        }

        let data = { ...printTaskList };
        // 向并发中添加任务
        runner.add(async (done) => {
            data.printer = printer;
            // 使用时间戳作为并发任务id
            let taskId = val.key;
            // 在taskMap中添加任务done事件
            taskMap[taskId] = done;
            data.taskId = taskId;
            data.data = await handeListPrintData(data);
            data.html = "";
            delete data.dataList;
            PRINT_WINDOW.webContents.send("print-new", data);
        });

        MAIN_WINDOW.webContents.send("printTask", Object.keys(taskMap).length);
    });

    //刷新打印机,上报云端--暂时注销这一行
    // sio.addMethod("refreshPrinter", syncPrinter);

    //在客户端中注册 ippRequest 方法
    sio.addMethod("ippRequest", function (options) {
        const { url, data } = options;
        try {
            let _data = ipp.serialize(data);
            ipp.request(url, _data, function (err, res) {
                err
                    ? sio
                        .writeAck("print.Error", {
                            msg: url + " 打印失败：" + err.message,
                            type: err.name,
                            res: res,
                        })
                        .then((value) => { })
                    : sio
                        .writeAck("print.Success", {
                            msg: url + " 打印成功",
                            type: err.name,
                            res: res,
                        })
                        .then((value) => { });
            });
        } catch (err) {
            sio
                .writeAck("print.Error", {
                    msg: url + " 打印失败：" + err.message,
                    type: err.name,
                })
                .then((value) => { });
        }
    });

    //在客户端中注册 获取IP、IPV6、MAC地址、DNS 方法
    sio.addMethod("getInfo", async function (data) {
        let { type, ...args } = data;
        switch (type) {
            case "ip":
                sio.writeAck("print.getInfo", { type: type, info: address.ip() });
                break;
            case "ipv6":
                sio.writeAck("print.getInfo", { type: type, info: address.ipv6() });
                break;
            case "mac":
                address.mac(function (err, addr) {
                    sio.writeAck("print.getInfo", {
                        type: type,
                        info: { addr: addr, err: err },
                    });
                });
                break;
            case "dns":
                address.dns(function (err, addr) {
                    sio.writeAck("print.getInfo", {
                        type: type,
                        info: { addr: addr, err: err },
                    });
                });
                break;
            case "interface":
                sio.writeAck("print.getInfo", {
                    type: type,
                    info: address.interface(...args),
                });
                break;
            case "all":
                address(function (err, addr) {
                    sio.writeAck("print.getInfo", {
                        type: type,
                        info: { addr: addr, err: err },
                    });
                });
                break;
            case "vboxnet":
                address("vboxnet", function (err, addr) {
                    sio.writeAck("print.getInfo", {
                        type: type,
                        info: { addr: addr, err: err },
                    });
                });
            default:
                address("all", function (err, addr) {
                    sio.writeAck("print.getInfo", {
                        type: type,
                        info: { addr: addr, err: err },
                    });
                });
                break;
        }
    });

    //监听模板返回
    sio.addMethod("syncTemp", function (data) {
        watchTemplateData = [...data];
    });
    //开始同步打印机
    while (true) {
        try {
            if (await syncPrinter(5000)) {
                console.log("打印控件启动同步打印机成功");
                MAIN_WINDOW.webContents.send("connection", true);
                break;
            }
            console.error("打印控件启动同步打印机失败,开始重试");
            MAIN_WINDOW.webContents.send("connection", false);
            await wait(10000);
        } catch (e) {
            console.error("打印控件启动同步打印机异常:", e);
            MAIN_WINDOW.webContents.send("connection", false);
            await wait(10000);
        }
    }

    console.log("创建iso完成时间", new Date().getTime());
}

module.exports = {
    initTray,
    initSocketNioClient
};